const express = require('express');
const helmet = require('helmet');
const http = require('http'); // 引入 http 模块
const { Server } = require('socket.io'); // 引入 Socket.IO
const bodyParser = require('body-parser');
const morgan = require('morgan');
const cors = require('cors');
const rateLimit = require('express-rate-limit'); // 引入速率限制
const mongoSanitize = require('express-mongo-sanitize'); //引入 MongoDB 防注入
const swaggerUi = require('swagger-ui-express'); // 引入 UI 库
const swaggerSpecs = require('./config/swagger.config'); // 引入配置的规范
require('dotenv').config(); // 加载 .env 文件

const app = express();
const PORT = process.env.PORT || 3000;

// 引入性能指标工具
const { register, metricsMiddleware } = require('./utils/metrics.util');
// 引入 Logger 配置
const logger = require('./config/logger.config');
// 引入数据库连接
const connectDB = require('./config/db.config.js');
const errorHandler = require('./middlewares/error.middleware');
connectDB(); // 连接数据库

// 创建HTTP服务
const server = http.createServer(app);
const io = new Server(server, {
    // 配置 CORS，Socket.IO 有单独的 CORS 配置
    cors: {
        origin: '*', // 允许所有来源访问 Socket.IO
        methods: ['GET', 'POST'],
    },
});

// --- Socket.IO 连接处理 ---
io.on('connection', (socket) => {
    console.log(`💬 一个新的用户连接: ${socket.id}`);

    // 监听客户端发送的 'chat message' 事件
    socket.on('chat message', (msg) => {
        console.log(`[${socket.id}] 收到消息: ${msg}`);
        // 广播消息给所有连接的客户端 (包括发送者)
        io.emit('chat message', msg);
    });

    // 监听断开连接事件
    socket.on('disconnect', () => {
        console.log(`🔌 用户断开连接: ${socket.id}`);
    });
});
// ----------------------------

// 详细配置 CORS 选项
const corsOptions = {
    origin: '*', // 允许所有来源访问，生产环境应改为允许您的前端域名，例如: 'https://yourfrontend.com'
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', // 允许的 HTTP 方法
    allowedHeaders: 'Content-Type,Authorization', // 允许的请求头
    credentials: true, // 允许发送 cookies (如果使用了 Session 或 Cookie 认证)
};

// --- 注册 Swagger 文档路由 ---
app.use(
    '/api-docs',
    swaggerUi.serve,
    swaggerUi.setup(swaggerSpecs, {
        explorer: true, // 允许在 UI 界面中搜索
    })
);
logger.info('📜 Swagger 文档接口已开放：/api-docs');

// --- 注册全局中间件 ---
app.use(cors(corsOptions)); // 注册 CORS
app.use(morgan('combined', { stream: logger.stream }));
app.use(bodyParser.json()); // 解析 JSON 格式请求体
app.use(bodyParser.urlencoded({ extended: false })); // 解析 URL-encoded 格式请求体
app.use(helmet());
app.use(
    helmet.contentSecurityPolicy({
        /* ... */
    })
);

// 速率限制 (DDoS / 暴力破解防范)
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 分钟窗口
    max: 100, // 窗口内每个 IP 限制 100 个请求
    message: '请求过于频繁，请稍后再试。',
    standardHeaders: true, // 返回速率限制信息
    legacyHeaders: false,
});
app.use(limiter); // 应用到所有请求
// MongoDB 操作符注入防范
app.use(mongoSanitize());
// 注册性能指标收集中间件 (必须在路由之前)
app.use(metricsMiddleware); // 注册性能监控中间件

// --- 路由 ---
const authRoutes = require('./routes/auth.routes');
const userRoutes = require('./routes/user.routes');
const { authenticateToken } = require('./middlewares/auth.middleware');
// 认证和验证码相关路由 (例如：/api/auth/login)
app.use('/api/auth', authRoutes);
// 示例：需要 Token 认证的路由
app.use('/api/user', authenticateToken, userRoutes);
// 静态文件服务：将所有对 /uploads 的请求映射到实际的 uploads 目录
app.use('/uploads', express.static('uploads'));
// 处理 404 错误
app.use((req, res, next) => {
    // 手动抛出 404 错误，它会被 errorHandler 捕获
    const err = new Error(`找不到路由: ${req.originalUrl}`);
    err.status = 404;
    next(err);
});

/**
 * @route GET /metrics
 * @desc Prometheus 抓取指标的端点
 * @access Public (通常只在内网暴露)
 */
app.get('/metrics', async (req, res) => {
    try {
        // 设置正确的响应头
        res.set('Content-Type', register.contentType);
        // 导出所有指标数据
        res.end(await register.metrics());
    } catch (ex) {
        // 记录错误，并返回 500
        logger.error('获取指标失败', { error: ex.message });
        res.status(500).end(ex);
    }
});

//  --- 全局中间件 --- 统一错误处理中间件 (必须放在所有路由和 404 之后)
app.use(errorHandler);

// --- 启动服务器 ---
server.listen(PORT, () => {
    console.log(`🚀 Server running on http://localhost:${PORT}`);
    console.log(`💬 WebSocket Server running on port ${PORT}`);
});
